﻿#pragma once

class Guard
{
public:
    Guard()
    {
        m_guard = new GuardHelper();
        m_host = true;
    }

    ~Guard()
    {
        if (m_host)
        {
            *(m_guard->m_vaild) = false;
        }

        --(*m_guard->m_refCounter);

        if (*(m_guard->m_refCounter) == 0)
        {
            delete m_guard;
        }
    }

    Guard(const Guard &other)
    {
        m_guard = other.m_guard;
        ++(*m_guard->m_refCounter);
        m_host = false;
    }

    Guard &operator=(const Guard &other)
    {
        if (&other == this)
        {
            return *this;
        }
        m_guard = other.m_guard;
        ++(*m_guard->m_refCounter);
        m_host = false;
        return *this;
    }

    operator bool()
    {
        return *m_guard->m_vaild;
    }

protected:
    struct GuardHelper
    {
        GuardHelper()
        {
            m_refCounter = new int;
            m_vaild = new bool;
            *m_refCounter = 1;
            *m_vaild = true;
        }

        ~GuardHelper()
        {
            delete m_refCounter;
            delete m_vaild;
        }

        int *m_refCounter;
        bool *m_vaild;
    };

private:
    GuardHelper *m_guard;
    bool m_host;
};

template <typename T>
class GuardPointer
{
public:
    GuardPointer(T *p)
        : m_p(p), m_guard(p->GetObjectGuard())
    {
    }

    T *operator->()
    {
        return m_p;
    }

    T &operator*()
    {
        return *m_p;
    }

    operator bool()
    {
        return m_guard;
    }

private:
    T *m_p;
    Guard m_guard;
};
